#include "BaseMQTTClient.h"
#include <chrono>
#include <thread>

BaseMQTTClient::BaseMQTTClient(const char *client_id, const char *host,
                               int port, int keep_alive_sec)
    : broker_host(host), broker_port(port), keep_alive(keep_alive_sec) {
  mosquitto_lib_init();

  // 创建一个新的 MQTT 客户端实例
  // 参数说明：
  // 1️⃣ client_id.c_str() : 客户端唯一标识符（Client ID）
  //     - 每个连接到同一 Broker 的客户端必须使用唯一 ID，否则会互相踢掉。
  //     - 用于让 Broker 区分不同的设备或程序实例。
  //
  // 2️⃣ true : Clean Session 标志位
  //     - true  表示“清除会话模式（Clean Session）”
  //       => 每次连接 Broker 都是全新会话，之前的订阅、消息记录都会被清空。
  //       => 一般适用于短连接或临时客户端。
  //     - false 表示“持久会话（Persistent Session）”
  //       => Broker 会保存上次连接的订阅状态、未收到的消息等。
  //       => 适合需要可靠消息投递的场景（例如设备掉线后自动续接）。
  //
  // 3️⃣ this : 用户上下文指针（void*）
  //     - 可以传任意自定义数据指针，这里传入当前对象指针 `this`。
  //     - 在回调函数（如 on_message、on_connect 等）被触发时，
  //       Mosquitto 库会把该指针原样传回，用于区分不同对象实例。
  //       例如：
  //           static void on_message_static(struct mosquitto*, void *obj, const
  //           mosquitto_message *msg) {
  //               MQTTClient *self = static_cast<MQTTClient *>(obj);
  //               self->on_message(msg);
  //           }
  //       这样实现 C 风格回调与 C++ 成员函数之间的桥接。
  //
  // 返回值说明：
  // - 返回一个 struct mosquitto* 指针（即 MQTT 客户端对象）。
  // - 若返回 NULL，说明内存分配失败或初始化出错。
  mosq = mosquitto_new(client_id, true, this); // this 用于回调

  if (!mosq) {
    std::cerr << "❌ 创建 Mosquitto 客户端失败" << std::endl;
    exit(1);
  }

  // 设置断开回调，用于自动重连
  mosquitto_disconnect_callback_set(mosq, BaseMQTTClient::on_disconnect);
}

BaseMQTTClient::~BaseMQTTClient() {
  disconnect();
  mosquitto_destroy(mosq);

  mosquitto_lib_cleanup();
}

bool BaseMQTTClient::connect() {
  // 连接到指定的 MQTT Broker（服务器）
  // -------------------------------------------------------------------
  // 函数：mosquitto_connect()
  // 作用：
  //   - 建立客户端与 MQTT Broker（如 Mosquitto 服务端）的 TCP 连接。
  //   - 并发送 MQTT CONNECT 报文，完成协议层握手。
  //   - 如果连接成功，客户端可以随后发布或订阅消息。
  //
  // 参数说明：
  //   mosq         -> 指向已创建的 mosquitto 客户端实例指针（由
  //   mosquitto_new() 返回） broker_host  -> MQTT 服务器的主机名或 IP
  //   地址（如 "localhost"、"192.168.5.11"） broker_port  -> MQTT
  //   服务器的端口号（通常为 1883，TLS 为 8883） keep_alive   ->
  //   保活时间（单位：秒）
  //                   若客户端在此时间内未与服务器通信，Broker
  //                   将认为客户端断开连接。
  //
  // 调用时机：
  //   ✅ 必须在成功调用 mosquitto_new() 创建客户端后调用。
  //   ✅ 若返回成功后，可进行订阅 (mosquitto_subscribe) 或发布
  //   (mosquitto_publish)。
  //
  // 返回值：
  //   - MOSQ_ERR_SUCCESS (0) ：连接成功
  //   - 其他错误码表示连接失败，例如：
  //        MOSQ_ERR_INVAL       -> 参数无效
  //        MOSQ_ERR_ERRNO       -> 底层 socket 错误（可通过 errno
  //        获取具体错误） MOSQ_ERR_NO_CONN     -> 未建立连接
  //
  // 示例：
  //     struct mosquitto *mosq = mosquitto_new("client1", true, NULL);
  //     int ret = mosquitto_connect(mosq, "192.168.5.11", 1883, 60);
  //     if (ret != MOSQ_ERR_SUCCESS) {
  //         std::cerr << "连接失败: " << mosquitto_strerror(ret) <<
  //         std::endl;
  //     } else {
  //         std::cout << "✅ 成功连接到 MQTT Broker" << std::endl;
  //     }
  //
  // 注意事项：
  //   - 该函数是同步调用（会阻塞直到连接建立或失败）。
  //   - 如果需要非阻塞连接，请使用 mosquitto_connect_async()。
  //   - 一旦连接成功，后续通过 mosquitto_loop_start() 维护通信循环。
  int ret =
      mosquitto_connect(mosq, broker_host.c_str(), broker_port, keep_alive);
  if (ret != MOSQ_ERR_SUCCESS) {
    std::cerr << "❌ 连接失败: " << mosquitto_strerror(ret) << std::endl;
    return false;
  }
  std::cout << "✅ 已连接到 MQTT Broker: " << broker_host << ":" << broker_port
            << std::endl;
  return true;
}

void BaseMQTTClient::disconnect() { mosquitto_disconnect(mosq); }

// -------------------------------------------------------------------
// 启动 MQTT 网络循环线程
// -------------------------------------------------------------------
//
// 1️⃣ 函数：mosquitto_loop_start()
// -------------------------------------------------------------
// 作用：
//   - 启动一个独立的后台线程，用于自动处理与 Broker 的通信。
//   - 包括：保持心跳、接收服务器推送的消息、处理重连与 QoS 消息确认。
//   - 一旦启动，该线程会持续运行，直到调用 mosquitto_loop_stop()。
//
// 参数：
//   mosq -> 指向已创建的 mosquitto 客户端实例。
//
// 返回值：
//   - MOSQ_ERR_SUCCESS 表示启动成功
//   - 其他错误码表示启动失败（如未初始化等）
//
// 注意：
//   ✅ 一般在成功连接（mosquitto_connect 成功）之后调用。
//   ✅ 启动后，消息回调函数（mosquitto_message_callback_set 设置的）
//      将在此线程中被异步触发。
//   ✅ 不需要手动调用 mosquitto_loop()，由后台线程自动完成。
//
void BaseMQTTClient::loop_start() { mosquitto_loop_start(mosq); }

// 2️⃣ 函数：mosquitto_loop_stop()
// -------------------------------------------------------------
// 作用：
//   - 停止由 mosquitto_loop_start() 启动的后台网络循环线程。
//   - 可在程序退出或需要重新配置连接时调用。
//
// 参数：
//   mosq   -> 指向已创建的 mosquitto 客户端实例。
//   force  -> 是否强制停止（布尔值）
//              true  = 立即终止线程（即使仍有未完成的网络操作）
//              false = 等待线程自然退出（推荐方式）
//
// 调用时机：
//   ✅ 程序结束前或 disconnect() 前调用，保证资源安全释放。
//   ⚠️ 若忘记调用，程序可能在退出时仍保留后台线程。
//
void BaseMQTTClient::loop_stop() { mosquitto_loop_stop(mosq, true); }

// 自动重连回调
// -------------------------------------------------------------------
// 回调函数：on_disconnect()
// -------------------------------------------------------------------
// 函数功能：
//   当 MQTT 客户端与 Broker 断开连接时由 mosquitto 库自动调用。
//   用于检测异常断线并自动执行重连逻辑，确保连接的持续性。
// -------------------------------------------------------------------
//
// 函数原型：
//   void on_disconnect(struct mosquitto *mosq, void *obj, int rc);
//
// 参数说明：
//   mosq -> 当前 MQTT 客户端实例指针。
//   obj  -> 用户自定义数据指针（在 mosquitto_new() 时传入，这里强制转换回
//   BaseMQTTClient*）。 rc   -> 断开原因码：
//            0  表示客户端主动断开（正常关闭）
//           ≠0  表示异常断开（例如网络中断、服务器关闭、心跳超时等）
//
// -------------------------------------------------------------------
// 实现逻辑：
//   1️⃣ 判断 rc 是否为 0：
//        - rc == 0 ：正常断开（如调用 disconnect()），无需重连。
//        - rc != 0 ：异常断开，执行自动重连机制。
//   2️⃣ 自动重连机制：
//        - 调用 mosquitto_reconnect() 尝试重连。
//        - 若失败，等待 5 秒后重试（形成循环重连机制）。
//        - 成功后打印提示信息 “✅ 重连成功”。
//   3️⃣ 注意：
//        - 此函数在 mosquitto 的内部网络线程中被触发。
//        - 若需要在 GUI
//        或业务线程中执行重连通知，应使用线程安全队列或回调事件机制。
// -------------------------------------------------------------------
//
// 调用时机：
//   - mosquitto_loop_start() 启动的后台线程检测到断线时会自动调用。
//   - 用户无需手动调用此函数。
void BaseMQTTClient::on_disconnect(struct mosquitto *mosq, void *obj, int rc) {
  BaseMQTTClient *client = static_cast<BaseMQTTClient *>(obj);
  (void)client;
  if (rc != 0) { // 非正常断开
    std::cerr << "⚠️ 连接断开，正在尝试重连..." << std::endl;
    int ret;
    do {
      ret = mosquitto_reconnect(mosq);
      if (ret != MOSQ_ERR_SUCCESS) {
        std::cerr << "⏳ 重连失败，5秒后重试..." << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(5));
      }
    } while (ret != MOSQ_ERR_SUCCESS);
    std::cout << "✅ 重连成功" << std::endl;
  }
}
